home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / DTS.Lib / GWLayers.c < prev    next >
Encoding:
Text File  |  1992-10-22  |  31.1 KB  |  1,111 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        GWLayers.c
  6. ** Written by:  Eric Soldan and Forrest Tanaka
  7. **
  8. ** Copyright © 1989-1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. */
  11.  
  12. /* This is an implementation of off-screen GWorld handling.  This particular
  13. ** implementation uses GWorlds in a hierarchical manner, with each layer in
  14. ** the hierarchy having its own tasks to handle at its specific level.
  15. ** The advantage to this is that it can conform to many applications.  Each
  16. ** application may need a different number of layers, and each layer may
  17. ** need to perform a different kind of operation.  By having an unlimited
  18. ** number of layers, and by having each layer handle its own application
  19. ** specific tasks, off-screen GWorld handling can be standardized.
  20. **
  21. ** A common use for off-screen stuff is to move an object around in a 
  22. ** window over a background.  To accomplish this, we need 3 layers.
  23. ** These are:
  24. **
  25. ** 1) The window layer.  This layer transfers a rectangle of pixels from
  26. **    the middle layer into the window layer, once the middle layer is ready.
  27. **    The rectangle transferred would be large enough to cover the old
  28. **    location and the new location, thus moving the piece without having
  29. **    to turn it off in the old location as a separate step.  This gives a
  30. **    very smooth appearance when moving an object.
  31. ** 2) A middle layer that is used to apply the object being moved to the
  32. **    background plus removing the object from the old location.  Once these
  33. **    two tasks are done, the off-screen work area is ready to be transferred
  34. **    to the window layer.
  35. ** 3) A background image against which the object moves.  This is used to
  36. **    restore the middle layer at the location where the object being moved
  37. **    was last at.
  38. **
  39. ** The top layer object relates to the window, and therefore we don't need an
  40. ** off-screen GWorld for it.  A call to create this layer might look like the below:
  41. **
  42. ** err = NewLayer(&windowLayer,   Layer object handle is returned here.
  43. **                nil,            Top layer, so there is no above layer.
  44. **                nil,            Uses default layer procedure.
  45. **                window,         Window used by the layer object.
  46. **                0,              Desired depth (0 for screen depth).
  47. **                0);             Custom layer init data, if any.
  48. **
  49. ** If NewLayer succeeds, the layer object handle is returned in windowLayer.
  50. ** If it fails, nil is returned in windowLayer, plus an error is returned.
  51. ** If windowLayer is successfully created, then we can proceed to create the
  52. ** next two layers.  In the case below, we are creating an off-screen layer
  53. ** that has a pixmap the same size and depth as windowLayer.  If this is
  54. ** what we want for the middle layer, then we can again use the default
  55. ** LayerProc for the kLayerInit message.  All we need to do is to call the
  56. ** default layerProc with a kLayerInit message.  We want the standard
  57. ** action for initialization, but we want our own update action.  That's
  58. ** why we have a custom layerProc for the middle layer.  The call would look
  59. ** something like the below:
  60. **
  61. ** err = NewLayer(&middleLayer,     Layer object handle is returned here.
  62. **                windowLayer,      Layer above this layer.
  63. **                MiddleLayerProc,  Custom layerProc.
  64. **                nil,              Create a pixmap for layer.
  65. **                0,                Pixmap created as same size/depth as above layer.
  66. **                0);
  67. **
  68. ** The background layer would be created similarly.  When you are finished with
  69. ** the layers, you can dispose of them one at a time with DisposeLayer, or you
  70. ** can dispose of all of them in the layer chain with DisposeThisAndBelowLayers.
  71. **
  72. ** Inserting a layer is done by position, and not by which layer it goes above
  73. ** or below.  The reason for this is that the layer positions are most likely
  74. ** absolute, and therefore it is better to indicate their position with an
  75. ** absolute number instead of always relating it to some other layer.  If it
  76. ** is necessary to insert a layer specifically above or below some other layer,
  77. ** it would be done as follows:
  78. **         InsertLayer(newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  79. **         InsertLayer(newLayer, belowLayer, GetLayerPosition(belowLayer));
  80. **
  81. ** The sample applications DTS.Draw and Kibitz uses the off-screen layer code.
  82. ** For a sample usage, see the file Window2.c in DTS.Draw, or Offscreen.c in Kibitz.
  83. */
  84.  
  85. /* NOTE:  Any calls that can be called first in this file that need to reference
  86. **        gQDVersion first call GetSystemInfo().  This guarantees that gQDVersion
  87. **        has been initialized correctly.  Calls that only reference gQDVersion
  88. **        should not be called first.  One example is DrawCIcon().  Assumably
  89. **        ReadCIcon() has already been called to get the icon. */
  90.  
  91.  
  92.  
  93. /*****************************************************************************/
  94.  
  95.  
  96.  
  97. #ifndef __ERRORS__
  98. #include "Errors.h"
  99. #endif
  100.  
  101. #ifndef __GWLAYERS__
  102. #include "GWLayers.h"
  103. #endif
  104.  
  105. #ifndef __RESOURCES__
  106. #include <Resources.h>
  107. #endif
  108.  
  109. #ifndef __UTILITIES__
  110. #include "Utilities.h"
  111. #endif
  112.  
  113.  
  114.  
  115. static OSErr    DefaultLayerInit(LayerObj theLayer);
  116. static OSErr    DefaultLayerDispose(LayerObj theLayer);
  117. static OSErr    DefaultLayerUpdate(LayerObj theLayer);
  118.  
  119. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds);
  120. static void        KillLayerWorld(LayerObj theLayer);
  121. static void        SmartGetGWorld(CGrafPtr *port, GDHandle *gdh);
  122. static void        SmartSetGWorld(CGrafPtr port, GDHandle gdh);
  123.  
  124.  
  125.  
  126. /*****************************************************************************/
  127. /*****************************************************************************/
  128.  
  129.  
  130.  
  131. #pragma segment GWLayers
  132. OSErr    NewLayer(LayerObj *newLayer, LayerObj aboveLayer, LayerProc theProc,
  133.                  GrafPtr basePort, short depth, unsigned long theData)
  134. {
  135.     OSErr        err;
  136.     LayerRecPtr    lptr;
  137.     CGrafPtr    scratchPort;
  138.     GDHandle    baseGDevice;
  139.  
  140.     GetSystemInfo();    /* Make sure gQDVersion is initialized. */
  141.  
  142.     *newLayer = (LayerObj)NewHandleClear(sizeof(LayerRec));
  143.     if (err = MemError()) return(err);
  144.         /* If not enough memory for layer object, return nil and error. */
  145.  
  146.     SmartGetGWorld(&scratchPort, &baseGDevice);
  147.     if (!theProc)
  148.         theProc = DefaultLayerProc;
  149.             /* If layer proc is nil, then they want the default behavior. */
  150.  
  151.     lptr = **newLayer;
  152.     lptr->layerPort     = basePort;
  153.     lptr->layerGDevice  = baseGDevice;
  154.     lptr->layerDepth    = depth;
  155.     lptr->xferMode      = srcCopy;
  156.     lptr->layerProc     = theProc;
  157.     lptr->layerData     = theData;
  158.         /* Layer object is now initialized, except for layers that need a GWorld
  159.         ** created.  This will occur when the layer proc is called with an
  160.         ** initialization message.  (All fields not explicitly set are 0.) */
  161.  
  162.     InsertLayer(*newLayer, aboveLayer, GetLayerPosition(aboveLayer) + 1);
  163.         /* Connect the layer to the layer chain.  The default initialization
  164.         ** behavior may need this, as it may create a GWorld of the same size
  165.         ** as the above layer.  If it isn't connected to the layer chain, then
  166.         ** there is no above layer. */
  167.  
  168.     if (err = (*theProc)(*newLayer, kLayerInit)) {
  169.         DisposeLayer(*newLayer);
  170.         *newLayer = nil;
  171.             /* There wasn't enough memory to create the off-screen GWorld, so
  172.             ** dispose of the layer object.  Since we failed, we need to return
  173.             ** nil and the error. */
  174.     }
  175.  
  176.     return(err);
  177. }
  178.  
  179.  
  180.  
  181. /*****************************************************************************/
  182.  
  183.  
  184.  
  185. #pragma segment GWLayers
  186. void    DetachLayer(LayerObj theLayer)
  187. {
  188.     LayerObj    aboveLayer, belowLayer;
  189.  
  190.     if (theLayer) {
  191.         aboveLayer = (*theLayer)->aboveLayer;
  192.         belowLayer = (*theLayer)->belowLayer;
  193.         if (aboveLayer)
  194.             (*aboveLayer)->belowLayer = belowLayer;
  195.         if (belowLayer)
  196.             (*belowLayer)->aboveLayer = aboveLayer;
  197.         (*theLayer)->aboveLayer = (*theLayer)->belowLayer = nil;
  198.     }
  199. }
  200.  
  201.  
  202.  
  203. /*****************************************************************************/
  204.  
  205.  
  206.  
  207. #pragma segment GWLayers
  208. OSErr    DisposeLayer(LayerObj theLayer)
  209. {
  210.     OSErr    err;
  211.  
  212.     err = noErr;
  213.     if (theLayer) {
  214.         err = (*((*theLayer)->layerProc))(theLayer, kLayerDispose);
  215.         DetachLayer(theLayer);
  216.         DisposeHandle((Handle)theLayer);
  217.     }
  218.  
  219.     return(err);
  220. }
  221.  
  222.  
  223.  
  224. /*****************************************************************************/
  225.  
  226.  
  227.  
  228. #pragma segment GWLayers
  229. OSErr    DisposeThisAndBelowLayers(LayerObj theLayer)
  230. {
  231.     OSErr    err, err2;
  232.  
  233.     err = noErr;
  234.     if (theLayer) {
  235.         err2 = DisposeThisAndBelowLayers((*theLayer)->belowLayer);
  236.         err  = DisposeLayer(theLayer);
  237.         if (!err)
  238.             err = err2;
  239.     }
  240.     return(err);
  241. }
  242.  
  243.  
  244.  
  245. /*****************************************************************************/
  246.  
  247.  
  248.  
  249. #pragma segment GWLayers
  250. short    GetLayerPosition(LayerObj theLayer)
  251. {
  252.     short    pos;
  253.  
  254.     if (!theLayer) return(0);
  255.  
  256.     for (pos = 0; theLayer = (*theLayer)->aboveLayer; ++pos);
  257.     return(pos);
  258. }
  259.  
  260.  
  261.  
  262. /*****************************************************************************/
  263.  
  264.  
  265.  
  266. #pragma segment GWLayers
  267. LayerObj    GetTopLayer(LayerObj theLayer)
  268. {
  269.     for (; (*theLayer)->aboveLayer; theLayer = (*theLayer)->aboveLayer);
  270.     return(theLayer);
  271. }
  272.  
  273.  
  274.  
  275. /*****************************************************************************/
  276.  
  277.  
  278.  
  279. #pragma segment GWLayers
  280. LayerObj    GetBottomLayer(LayerObj theLayer)
  281. {
  282.     for (; (*theLayer)->belowLayer; theLayer = (*theLayer)->belowLayer);
  283.     return(theLayer);
  284. }
  285.  
  286.  
  287.  
  288. /*****************************************************************************/
  289.  
  290.  
  291.  
  292. #pragma segment GWLayers
  293. void    InsertLayer(LayerObj theLayer, LayerObj referenceLayer, short pos)
  294. {
  295.     LayerObj    aboveLayer, belowLayer;
  296.     short        i;
  297.  
  298.     if (theLayer) {
  299.         if (theLayer == referenceLayer) {
  300.             /* If theLayer layer is the same as referenceLayer... */
  301.  
  302.             if (belowLayer = (*theLayer)->belowLayer)
  303.                 referenceLayer = belowLayer;
  304.             if (aboveLayer = (*theLayer)->aboveLayer)
  305.                 referenceLayer = aboveLayer;
  306.                     /* Try to make the reference layer not the same as theLayer.
  307.                     ** If it is the same as theLayer, then when theLayer is
  308.                     ** removed from the old hierarchy, we lose the ability to re-add
  309.                     ** it to the hierarchy in a new location. */
  310.         }
  311.  
  312.         DetachLayer(theLayer);
  313.             /* Remove layer from its old hierarchy, if any. */
  314.  
  315.         if (!referenceLayer) return;
  316.             /* If there isn't a valid alternative reference, then theLayer
  317.             ** IS the hierarchy and no action is taken. */
  318.  
  319.         aboveLayer = nil;
  320.         belowLayer = GetTopLayer(referenceLayer);
  321.             /* aboveLayer now nil.  belowLayer now is top layer.  These
  322.             ** are the correct values if the layer being added is to be
  323.             ** the new top layer.  This will be the case if pos is 0.
  324.             ** We now walk the linked list pos number of times to get the
  325.             ** correct position.  We also terminate if we reach the end
  326.             ** of the linked list, no matter what pos is.  This will allow
  327.             ** values of pos that are too big to insert the layer at the
  328.             ** end of the linked list. */
  329.  
  330.         for (i = 0; ((belowLayer) && (i != pos)); ++i) {
  331.             aboveLayer = belowLayer;
  332.             belowLayer = (*belowLayer)->belowLayer;
  333.         }
  334.             /* We now have correct values for aboveLayer and belowLayer.  Note that
  335.             ** these values may be nil, which would be correct. */
  336.         if ((*theLayer)->aboveLayer = aboveLayer)
  337.             (*aboveLayer)->belowLayer = theLayer;
  338.         if ((*theLayer)->belowLayer = belowLayer)
  339.             (*belowLayer)->aboveLayer = theLayer;
  340.     }
  341. }
  342.  
  343.  
  344.  
  345. /*****************************************************************************/
  346.  
  347.  
  348.  
  349. #pragma segment GWLayers
  350. OSErr    UpdateLayer(LayerObj theLayer)
  351. {
  352.     OSErr    err;
  353.  
  354.     err = noErr;
  355.     if (theLayer) {
  356.         err = UpdateLayer((*theLayer)->belowLayer);
  357.             /* Handle the updates from the bottom up. */
  358.         if (!err)
  359.             err = (*((*theLayer)->layerProc))(theLayer, kLayerUpdate);
  360.                 /* Chain possible errors through each level of recursion. */
  361.     }
  362.     return(err);
  363. }
  364.  
  365.  
  366.  
  367. /*****************************************************************************/
  368.  
  369.  
  370.  
  371. #pragma segment GWLayers
  372. Rect    GetEffectiveSrcRect(LayerObj theLayer)
  373. {
  374.     Rect    srcRect;
  375.  
  376.     if (!theLayer)
  377.         SetRect(&srcRect, 0, 0, 0, 0);
  378.     else {
  379.         srcRect = (*theLayer)->srcRect;
  380.         if (EmptyRect(&srcRect))
  381.             srcRect = ((*theLayer)->layerPort)->portRect;
  382.     }
  383.     return(srcRect);
  384. }
  385.  
  386.  
  387.  
  388. /*****************************************************************************/
  389.  
  390.  
  391.  
  392. #pragma segment GWLayers
  393. Rect    GetEffectiveDstRect(LayerObj theLayer)
  394. {
  395.     Rect    dstRect;
  396.  
  397.     if (!theLayer)
  398.         SetRect(&dstRect, 0, 0, 0, 0);
  399.     else {
  400.         dstRect = (*theLayer)->dstRect;
  401.         if (EmptyRect(&dstRect))
  402.             dstRect = ((*theLayer)->layerPort)->portRect;
  403.     }
  404.     return(dstRect);
  405. }
  406.  
  407.  
  408.  
  409. /*****************************************************************************/
  410.  
  411.  
  412.  
  413. #pragma segment GWLayers
  414. OSErr    DefaultLayerProc(LayerObj theLayer, short message)
  415. {
  416.     OSErr    err;
  417.  
  418.     err = noErr;
  419.     if (theLayer) {
  420.         switch (message) {        /* Dispatch to the correct default behavior. */
  421.             case kLayerInit:
  422.                 err = DefaultLayerInit(theLayer);
  423.                 break;
  424.             case kLayerDispose:
  425.                 err = DefaultLayerDispose(theLayer);
  426.                 break;
  427.             case kLayerUpdate:
  428.                 err = DefaultLayerUpdate(theLayer);
  429.                 break;
  430.             default:
  431.                 break;
  432.         }
  433.     }
  434.     return(err);
  435. }
  436.  
  437.  
  438.  
  439. /*****************************************************************************/
  440.  
  441.  
  442.  
  443. #pragma segment GWLayers
  444. static OSErr    DefaultLayerInit(LayerObj theLayer)
  445. {
  446.     LayerObj    aboveLayer;
  447.     GWorldPtr    layerWorld;        /* GWorld for this layer. */
  448.     Rect        parentRect;        /* Rectangle of parent in global coordinates. */
  449.     GrafPtr        parentPort;        /* Parent layer's GrafPort. */
  450.     GDHandle    parentGDevice;    /* Parent layer's GDevice. */
  451.     CGrafPtr    keepPort;        /* Saved GrafPort. */
  452.     GDHandle    keepGDevice;    /* Saved GDevice. */
  453.     Point        org;
  454.     OSErr        err;
  455.  
  456.     err = noErr;
  457.     if (theLayer) {
  458.         if (!(*theLayer)->layerPort) {
  459.  
  460.             if (aboveLayer = (*theLayer)->aboveLayer) {
  461.                 /* The default behavior is to create a GWorld the same size
  462.                 ** as the above layer, if there is one.  If there isn't an above
  463.                 ** layer and we were expected to create a GWorld, we have problems.
  464.                 ** This situation can't be resolved and is handled as a paramErr. */
  465.  
  466.                 SmartGetGWorld(&keepPort, &keepGDevice);        /* Keep the GWorld. */
  467.  
  468.                 parentPort    = (*aboveLayer)->layerPort;
  469.                 parentGDevice = (*aboveLayer)->layerGDevice;
  470.                     /* Grab the parent layer's GrafPort and GDevice. */
  471.     
  472.                 SmartSetGWorld((CGrafPtr)parentPort, parentGDevice);
  473.                 parentRect = GetEffectiveDstRect(aboveLayer);
  474.                     /* The default behavior is to use the portRect of the above
  475.                     ** port.  This behavior can be overridden if desired by setting
  476.                     ** dstRect.  dstRect is initialized to be empty, but if
  477.                     ** it is specifically set, then this layer should map into
  478.                     ** just the dstRect and not the portRect.  This is useful if
  479.                     ** the off-screen image is to be displayed in only a portion
  480.                     ** of a window. */
  481.  
  482.                 org.h = parentRect.left;
  483.                 org.v = parentRect.top;
  484.                 LocalToGlobalRect(&parentRect);
  485.                     /* Put the parent layer's destination rect in global coordinates. */
  486.     
  487.                 if (gQDVersion)
  488.                     err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &parentRect, nil, nil, 0);
  489.                         /* Create the GWorld for this layer.  It will be created with the
  490.                         ** requested depth.  If the requested depth is 0, then it will be
  491.                         ** created with a depth great enough for the deepest monitor the
  492.                         ** parentRect intersects. */
  493.                 else
  494.                     err = MakeLayerWorld(&layerWorld, theLayer, parentRect);
  495.                         /* Create a bitmap for those systems without GWorlds. */
  496.  
  497.                 if (err == noErr) {
  498.                     (*theLayer)->layerOwnsPort = true;
  499.                     SetPort((*theLayer)->layerPort = (GrafPtr)layerWorld);
  500.                         /* Save the new GWorld in the layer object. */
  501.                     SetOrigin(org.h, org.v);
  502.                         /* Set the origin so that this GWorld maps directly into the
  503.                         ** area to be copied into (dstRect or portRect) for the
  504.                         ** above layer. */
  505.                 }
  506.  
  507.                 SmartSetGWorld(keepPort, keepGDevice);        /* Restore the kept GWorld. */
  508.             }
  509.             else {
  510.                 err = paramErr;
  511.                     /* We were expected to create an off-screen GWorld of the
  512.                     ** same size as the above layer, but we didn't have an above
  513.                     ** layer.  This is an error.  The parameters passed to NewLayer
  514.                     ** were inappropriate for the situation, so return a paramErr. */
  515.             }
  516.         }
  517.     }
  518.     return(err);
  519. }
  520.  
  521.  
  522.  
  523. /*****************************************************************************/
  524.  
  525.  
  526.  
  527. #pragma segment GWLayers
  528. Rect    UpdateUpdateRects(LayerObj theLayer)
  529. {
  530.     Rect    lastUpdate, thisUpdate, dstRect;
  531.  
  532.     if (theLayer) {
  533.         lastUpdate = (*theLayer)->lastUpdate;
  534.         (*theLayer)->lastUpdate = thisUpdate = (*theLayer)->thisUpdate;
  535.         SetRect(&((*theLayer)->thisUpdate), 0, 0, 0, 0);
  536.  
  537.         if ((*theLayer)->includeLastUpdate) {
  538.             (*theLayer)->includeLastUpdate = false;
  539.             if (EmptyRect(&lastUpdate))
  540.                 lastUpdate = thisUpdate;
  541.             if (EmptyRect(&thisUpdate))
  542.                 thisUpdate = lastUpdate;
  543.             UnionRect(&thisUpdate, &lastUpdate, &thisUpdate);
  544.                 /* We are going to update the last and current update rects.
  545.                 ** This will allow the appearance of movement for a foreground
  546.                 ** object.  The old location is cleared, plus the new location
  547.                 ** is updated. */
  548.             dstRect = GetEffectiveDstRect(theLayer);
  549.             SectRect(&thisUpdate, &dstRect, &thisUpdate);
  550.         }
  551.     }
  552.     else SetRect(&thisUpdate, 0, 0, 0, 0);
  553.  
  554.     return(thisUpdate);
  555. }
  556.  
  557.  
  558.  
  559. /*****************************************************************************/
  560.  
  561.  
  562.  
  563. #pragma segment GWLayers
  564. static OSErr    DefaultLayerUpdate(LayerObj theLayer)
  565. {
  566.     LayerObj    belowLayer;
  567.     GrafPtr        belowPort, thisPort;
  568.     GDHandle    thisGDevice;
  569.     CGrafPtr    keepPort;
  570.     GDHandle    keepGDevice;
  571.     Rect        thisUpdate, belowRect, thisRect;
  572.     short        xfer;
  573.     RgnHandle    rgn;
  574.  
  575.     /* The default update behavior is to copy the area to be updated from the
  576.     ** below layer into the indicated layer.  We only need to update layer if
  577.     ** there is a below layer.  The bottom-most layer update doesn't do anything.
  578.     ** As a default, the bottom-most layer is considered background and does not
  579.     ** get updated. */
  580.  
  581.     if (theLayer) {
  582.         if (belowLayer = (*theLayer)->belowLayer) {
  583.             /* Get this layer's GWorld and below layer's port. */
  584.             thisPort    = (*theLayer)->layerPort;
  585.             thisGDevice = (*theLayer)->layerGDevice;
  586.             belowPort   = (*belowLayer)->layerPort;
  587.  
  588.             /* Save current GWorld and set the parent's GWorld. */
  589.             SmartGetGWorld(&keepPort, &keepGDevice);
  590.             SmartSetGWorld((CGrafPtr)thisPort, thisGDevice);
  591.  
  592.             thisUpdate = UpdateUpdateRects(theLayer);
  593.  
  594.             rgn = NewRgn();
  595.             RectRgn(rgn, &thisUpdate);
  596.  
  597.             belowRect = GetEffectiveSrcRect(belowLayer);
  598.             thisRect  = GetEffectiveDstRect(theLayer);
  599.  
  600.                 /* As a default behavior, we CopyBits the below layer into this layer. */
  601.             LockLayerWorld(belowLayer);
  602.             LockLayerWorld(theLayer);
  603.             xfer = (*theLayer)->xferMode;
  604.             CopyBits(&belowPort->portBits, &thisPort->portBits, &belowRect, &thisRect, xfer, rgn);
  605.             UnlockLayerWorld(theLayer);
  606.             UnlockLayerWorld(belowLayer);
  607.             DisposeRgn(rgn);
  608.  
  609.             SmartSetGWorld(keepPort, keepGDevice);        /* Restore to the kept GWorld. */
  610.         }
  611.     }
  612.     return(noErr);
  613. }
  614.  
  615.  
  616.  
  617. /*****************************************************************************/
  618.  
  619.  
  620.  
  621. #pragma segment GWLayers
  622. static OSErr    DefaultLayerDispose(LayerObj theLayer)
  623. {
  624.     GWorldPtr    theWorld;
  625.  
  626.     if (theLayer) {
  627.         if ((*theLayer)->layerOwnsPort) {
  628.             if (theWorld = (GWorldPtr)(*theLayer)->layerPort) {
  629.                 if ((*theLayer)->layerBitmap)
  630.                     KillLayerWorld(theLayer);
  631.                 else
  632.                     DisposeGWorld(theWorld);
  633.             }
  634.         }
  635.     }
  636.  
  637.     return(noErr);
  638. }
  639.  
  640.  
  641.  
  642. /*****************************************************************************/
  643.  
  644.  
  645.  
  646. #pragma segment GWLayers
  647. void    InvalLayer(LayerObj theLayer, Rect invalRect, Boolean includeLastUpdate)
  648. {
  649.     Rect        thisUpdate, srcRect, dstRect;
  650.     LayerObj    belowLayer;
  651.     short        ow, oh;
  652.     long        dw, dh, sw, sh;
  653.  
  654.     if (theLayer) {
  655.         belowLayer = (*theLayer)->belowLayer;
  656.         dstRect    = GetEffectiveDstRect(theLayer);
  657.  
  658.         SectRect(&dstRect, &invalRect, &invalRect);
  659.         if (!EmptyRect(&invalRect)) {                /* If there is something to invalidate... */
  660.             thisUpdate = (*theLayer)->thisUpdate;    /* There may be a prior unhandled update... */
  661.             if (EmptyRect(&thisUpdate))
  662.                 thisUpdate = invalRect;                /* UnionRect doesn't */
  663.             UnionRect(&thisUpdate, &invalRect, &(*theLayer)->thisUpdate);    /* like empty rects. */
  664.  
  665.             if (belowLayer) {
  666.                 /* If we have a below layer, then pass the update down.  The effectiveSrcRct
  667.                 ** rect for the below layer may be a different size than the effectiveDstRct.
  668.                 ** If this is the case, we want to scale invalRect to invalidate a proportional
  669.                 ** area in the below layer. */
  670.  
  671.                 srcRect = GetEffectiveSrcRect(belowLayer);
  672.  
  673.                 dw = dstRect.right  - dstRect.left;        /* Calculate widths and heights for */
  674.                 dh = dstRect.bottom - dstRect.top;        /* srcRect and dstRect. */
  675.                 sw = srcRect.right  - srcRect.left;
  676.                 sh = srcRect.bottom - srcRect.top;
  677.  
  678.                 OffsetRect(&invalRect, -dstRect.left, -dstRect.top);
  679.                     /* We want to align the upper-left corner of the srcRect and dstRect
  680.                     ** so that the scaling also aligns the invalRect into the correct
  681.                     ** place in the below layer's effectiveSrcRect.  invalRect is now
  682.                     ** positioned relative to a dstRect with a upper-left corner of 0,0. */
  683.  
  684.                 if (dw != sw) {        /* Width dstRect different than srcRect. */
  685.                     ow = invalRect.right  - invalRect.left;
  686.                     invalRect.left  = (short)((invalRect.left  * sw) / dw);
  687.                     invalRect.right = (short)((invalRect.right * sw) / dw);
  688.                     if ((((invalRect.right  - invalRect.left) * dw) / sw) != ow)
  689.                         ++invalRect.right;
  690.                             /* We can possibly lose a fraction of a pixel on the right edge when
  691.                             ** scaling the invalRect.  It won't hurt if we inval just a bit too
  692.                             ** much, whereas invalidating too little is a bad thing. */
  693.                 }
  694.  
  695.                 if (dh != sh) {        /* Height dstRect different than srcRect. */
  696.                     oh = invalRect.bottom - invalRect.top;
  697.                     invalRect.top    = (short)((invalRect.top    * sh) / dh);
  698.                     invalRect.bottom = (short)((invalRect.bottom * sh) / dh);
  699.                     if ((((invalRect.bottom - invalRect.top ) * dh) / sh) != oh)
  700.                         ++invalRect.bottom;
  701.                 }
  702.  
  703.                 OffsetRect(&invalRect, srcRect.left, srcRect.top);
  704.                     /* Displace the new invalRect correctly relative to the srcRect. */
  705.             }
  706.         }
  707.  
  708.         if (includeLastUpdate)
  709.             (*theLayer)->includeLastUpdate = true;
  710.                 /* If requested to update last position as well, flag it. */
  711.  
  712.         InvalLayer(belowLayer, invalRect, includeLastUpdate);
  713.             /* Invalidate the below layer with the new (possibly scaled) invalRect. */
  714.     }
  715. }
  716.  
  717.  
  718. /*****************************************************************************/
  719.  
  720.  
  721.  
  722. #pragma segment GWLayers
  723. void    SetLayerWorld(LayerObj theLayer)
  724. {
  725.     CGrafPtr    keepPort;
  726.     GDHandle    keepGDevice;
  727.  
  728.     /* This is a convenient call for setting a GWorld, while remembering what
  729.     ** the previous GWorld was.  This should be balanced with a call to
  730.     ** ResetLayerWorld.  A count of how many times this is called is kept
  731.     ** so that the old GWorld is cached only if SetLayerWorld is currently
  732.     ** in balance with ResetLayerWorld.  This keeps the oldest kept GWorld
  733.     ** from being overwritten by subsequent calls. */
  734.  
  735.     if (theLayer) {
  736.         if (!(*theLayer)->cachedCount++) {
  737.             SmartGetGWorld(&keepPort, &keepGDevice);
  738.             (*theLayer)->cachedPort    = keepPort;
  739.             (*theLayer)->cachedGDevice = keepGDevice;
  740.         }
  741.         SmartSetGWorld((CGrafPtr)(*theLayer)->layerPort, (*theLayer)->layerGDevice);
  742.         LockLayerWorld(theLayer);
  743.     }
  744. }
  745.  
  746.  
  747.  
  748. /*****************************************************************************/
  749.  
  750.  
  751.  
  752. #pragma segment GWLayers
  753. void    ResetLayerWorld(LayerObj theLayer)
  754. {
  755.     /* This is used to undo a call to SetLayerWorld.  Calls to ResetLayerWorld
  756.     ** should be balanced with previous calls to SetLayerWorld. */
  757.  
  758.     if (theLayer) {
  759.         UnlockLayerWorld(theLayer);
  760.         if (!--(*theLayer)->cachedCount)
  761.             SmartSetGWorld((*theLayer)->cachedPort, (*theLayer)->cachedGDevice);
  762.     }
  763. }
  764.  
  765.  
  766.  
  767. /*****************************************************************************/
  768.  
  769.  
  770.  
  771. #pragma segment GWLayers
  772. void    LockLayerWorld(LayerObj theLayer)
  773. {
  774.     Handle    bitmap;
  775.  
  776.     /* This is a convenient way to lock down the pixels for a layer's GWorld.
  777.     ** A locked count is kept to make sure that the GWorld is locked only the
  778.     ** first time this is called.  Calls to LockLayerWorld will most likely
  779.     ** be balanced by calls to UnlockLayerWorld, but not necessarily.  It may
  780.     ** be desirable to keep a GWorld call locked.  In this case, right after
  781.     ** creating the layer (and indirectly its GWorld), call LockLayerWorld.
  782.     ** This will initially lock it.  Subsequent calls would be balanced, and
  783.     ** therefore there will always be one more LockLayerWorld call than
  784.     ** UnlockLayerWorld calls.  This will keep it locked. */
  785.  
  786.     if (theLayer) {
  787.         if ((*theLayer)->layerOwnsPort) {
  788.             if (!(*theLayer)->lockedCount++) {
  789.                 if (bitmap = (*theLayer)->layerBitmap) {
  790.                     HLock(bitmap);
  791.                     (*theLayer)->layerPort->portBits.baseAddr = *bitmap;
  792.                 }
  793.                 else
  794.                     LockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  795.             }
  796.         }
  797.     }
  798. }
  799.  
  800.  
  801.  
  802. /*****************************************************************************/
  803.  
  804.  
  805.  
  806. #pragma segment GWLayers
  807. void    UnlockLayerWorld(LayerObj theLayer)
  808. {
  809.     Handle    bitmap;
  810.  
  811.     /* This undoes what LockLayerWorld does.  Calls to UnlockLayerWorld will
  812.     ** generally be balanced with calls to LockLayerWorld. */
  813.  
  814.     if (theLayer) {
  815.         if ((*theLayer)->layerOwnsPort) {
  816.             if (!--(*theLayer)->lockedCount) {
  817.                 if (bitmap = (*theLayer)->layerBitmap)
  818.                     HUnlock(bitmap);
  819.                 else
  820.                     UnlockPixels(GetGWorldPixMap((GWorldPtr)(*theLayer)->layerPort));
  821.             }
  822.         }
  823.     }
  824. }
  825.  
  826.  
  827.  
  828. /*****************************************************************************/
  829.  
  830.  
  831.  
  832. #pragma segment GWLayers
  833. RgnHandle    ScreenDepthRegion(short depth)
  834. {
  835.     RgnHandle        retRgn, tmpRgn;
  836.     GDHandle        device;
  837.     PixMapHandle    pmap;
  838.     Rect            rct;
  839.  
  840.     GetSystemInfo();    /* Make sure gQDVersion is initialized. */
  841.  
  842.     retRgn = NewRgn();
  843.  
  844.     if (gQDVersion == kQDOriginal) {
  845.         if (depth == 1) {
  846.             rct = GetMainScreenRect();
  847.             RectRgn(retRgn, &rct);
  848.         }
  849.     }
  850.     else {
  851.         tmpRgn = NewRgn();
  852.         for (device = GetDeviceList(); device; device = GetNextDevice(device)) {
  853.             if (
  854.                 (TestDeviceAttribute(device, screenDevice)) &&
  855.                 (TestDeviceAttribute(device, screenActive))
  856.             ) {
  857.                 pmap = (*device)->gdPMap;
  858.                 if ((*pmap)->pixelSize >= depth) {
  859.                     rct = (*device)->gdRect;
  860.                     RectRgn(tmpRgn, &rct);
  861.                     UnionRgn(retRgn, tmpRgn, retRgn);
  862.                 }
  863.             }
  864.         }
  865.         DisposeRgn(tmpRgn);
  866.     }
  867.  
  868.     return(retRgn);
  869. }
  870.  
  871.  
  872.  
  873. /*****************************************************************************/
  874.  
  875.  
  876.  
  877. #pragma segment GWLayers
  878. CIconHandle    ReadCIcon(short iconID)
  879. {
  880.     Handle    hndl;
  881.  
  882.     GetSystemInfo();    /* Make sure gQDVersion is initialized. */
  883.  
  884.     if (gQDVersion == kQDOriginal) {
  885.         hndl = GetResource('cicn', iconID);
  886.         DetachResource(hndl);
  887.         return((CIconHandle)hndl);
  888.     }
  889.  
  890.     return(GetCIcon(iconID));
  891. }
  892.  
  893.  
  894.  
  895. /*****************************************************************************/
  896.  
  897.  
  898.  
  899. #pragma segment GWLayers
  900. void    KillCIcon(CIconHandle icon)
  901. {
  902.     if (gQDVersion == kQDOriginal)
  903.         DisposeHandle((Handle)icon);
  904.     else
  905.         DisposeCIcon(icon);
  906. }
  907.  
  908.  
  909.  
  910. /*****************************************************************************/
  911.  
  912.  
  913.  
  914. #pragma segment GWLayers
  915. void    DrawCIcon(CIconHandle icon, Rect destRect)
  916. {
  917.     if (gQDVersion == kQDOriginal)
  918.         DrawCIconByDepth(icon, destRect, 1, true);
  919.     else
  920.         PlotCIcon(&destRect, icon);
  921. }
  922.  
  923.  
  924.  
  925. /*****************************************************************************/
  926.  
  927.  
  928.  
  929. #pragma segment GWLayers
  930. void    DrawCIconNoMask(CIconHandle icon, Rect destRect)
  931. {
  932.     Rect    iconRect;
  933.     char    oldMask[128], *mptr;
  934.     short    maskSize, i;
  935.  
  936.     mptr = (Ptr)(*icon)->iconMaskData;
  937.     iconRect = (*icon)->iconPMap.bounds;
  938.     maskSize = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  939.     for (i = 0; i < maskSize; ++i) {
  940.         oldMask[i] = mptr[i];
  941.         mptr[i] = 0xFF;
  942.     }
  943.     DrawCIcon(icon, destRect);
  944.     mptr = (Ptr)(*icon)->iconMaskData;
  945.     for (i = 0; i < maskSize; ++i) mptr[i] = oldMask[i];
  946. }
  947.  
  948.  
  949.  
  950. /*****************************************************************************/
  951.  
  952.  
  953.  
  954. #pragma segment GWLayers
  955. void    DrawCIconByDepth(CIconHandle icon, Rect destRect, short depth, Boolean useMask)
  956. {
  957.     GrafPtr        thePort;
  958.     char        savedIconState;
  959.     char        savedDataState;
  960.     short        offset;
  961.     BitMapPtr    bmap;
  962.     Rect        iconRect;
  963.  
  964.     GetPort(&thePort);
  965.  
  966.     if (!depth) {
  967.         if (!(thePort->portBits.rowBytes & 0x8000))
  968.             depth = 1;
  969.         else
  970.             depth = (*(((CGrafPtr)thePort)->portPixMap))->pixelSize;
  971.     }
  972.  
  973.     savedIconState = HGetState((Handle)icon);        /* Lock down things. */
  974.     HLock((Handle)icon);
  975.     if (depth > 1) {
  976.         savedDataState = HGetState((*icon)->iconData);
  977.         HLock((*icon)->iconData);
  978.         (*icon)->iconPMap.baseAddr = *((*icon)->iconData);
  979.             /* Point the icon's pixMap at the color icon data. */
  980.     }
  981.  
  982.     iconRect = (*icon)->iconPMap.bounds;
  983.         /* Find out the dimensions of the icon. */
  984.  
  985.     (*icon)->iconMask.baseAddr = (Ptr)(*icon)->iconMaskData;
  986.         /* Point the mask's bitMap at the mask data. */
  987.  
  988.     offset = (iconRect.bottom - iconRect.top) * (*icon)->iconMask.rowBytes;
  989.     (*icon)->iconBMap.baseAddr = (*icon)->iconMask.baseAddr + offset;
  990.         /* Point the icon's bitMap at the b/w icon data. */
  991.  
  992.     bmap = (depth == 1) ? (BitMapPtr)&((*icon)->iconBMap) : (BitMapPtr)&((*icon)->iconPMap);
  993.     if (useMask)
  994.         CopyMask(bmap, &((*icon)->iconMask), &thePort->portBits, &iconRect, &iconRect, &destRect);
  995.     else
  996.         CopyBits(bmap, &thePort->portBits, &iconRect, &destRect, srcCopy, nil);
  997.  
  998.     HSetState((Handle)icon, savedIconState);        /* Unlock things. */
  999.     if (depth > 1)
  1000.         HSetState((*icon)->iconData, savedDataState);
  1001. }
  1002.  
  1003.  
  1004.  
  1005. /*****************************************************************************/
  1006.  
  1007.  
  1008.  
  1009. #pragma segment GWLayers
  1010. static OSErr    MakeLayerWorld(GWorldPtr *layerWorld, LayerObj theLayer, Rect bnds)
  1011. {
  1012.     GrafPtr    oldPort;
  1013.     GrafPtr    newPort;
  1014.     Handle    bitmap;
  1015.     OSErr    err;
  1016.  
  1017.     OffsetRect(&bnds, -bnds.left, -bnds.top);    /* Make sure upper-left is 0,0. */
  1018.  
  1019.     GetPort(&oldPort);        /* Need this to restore thePort after OpenPort. */
  1020.  
  1021.     newPort = (GrafPtr)NewPtr(sizeof(GrafPort));        /* Allocate the grafPort. */
  1022.     if (err = MemError())
  1023.         return(err);        /* Failed to allocate the off-screen port. */
  1024.  
  1025.     /* The call to OpenPort does the following:
  1026.     ** 1) allocates space for visRgn (set to screenBits.bounds) and clipRgn (set wide open)
  1027.     ** 2) sets portBits to screenBits
  1028.     ** 3) sets portRect to screenBits.bounds, etc. (see IM I-163,164)
  1029.     ** 4) side effect: does a SetPort(&offScreen) */
  1030.  
  1031.     OpenPort(newPort);
  1032.     SetPort(oldPort);
  1033.  
  1034.         /* Now make bitmap the size of the bounds that caller supplied. */
  1035.  
  1036.     newPort->portRect = bnds;
  1037.     newPort->portBits.bounds = bnds;
  1038.     RectRgn(newPort->visRgn, &bnds);
  1039.  
  1040.     SetRectRgn(newPort->clipRgn, -32000, -32000, 32000, 32000);
  1041.         /* Avoid wide-open clipRgn, to be safe.    */
  1042.  
  1043.     /* rowBytes is size of row, it must be rounded up to an even number of bytes. */
  1044.     newPort->portBits.rowBytes = ((bnds.right - bnds.left + 15) >> 4) << 1;
  1045.  
  1046.     bitmap = NewHandle(newPort->portBits.rowBytes * (long)(bnds.bottom - bnds.top));
  1047.     if (err = MemError()) {
  1048.         ClosePort(newPort);            /* Dump the visRgn and clipRgn. */
  1049.         DisposPtr((Ptr)newPort);    /* Dump the GrafPort. */
  1050.         return(err);
  1051.     }
  1052.  
  1053.     (*theLayer)->layerBitmap = bitmap;
  1054.     *layerWorld              = (GWorldPtr)newPort;
  1055.  
  1056.     return(noErr);
  1057. }
  1058.  
  1059.  
  1060.  
  1061. /*****************************************************************************/
  1062.  
  1063.  
  1064.  
  1065. #pragma segment GWLayers
  1066. static void    KillLayerWorld(LayerObj theLayer)
  1067. {
  1068.     DisposeHandle((*theLayer)->layerBitmap);
  1069.     (*theLayer)->layerBitmap = nil;
  1070.  
  1071.     ClosePort((*theLayer)->layerPort);
  1072.     DisposePtr((Ptr)(*theLayer)->layerPort);
  1073.     (*theLayer)->layerPort = nil;
  1074. }
  1075.  
  1076.  
  1077.  
  1078.  
  1079. /*****************************************************************************/
  1080.  
  1081.  
  1082.  
  1083. #pragma segment GWLayers
  1084. static void    SmartGetGWorld(CGrafPtr *port, GDHandle *gdh)
  1085. {
  1086.     if (gQDVersion)
  1087.         GetGWorld(port, gdh);
  1088.     else {
  1089.         *gdh = nil;
  1090.         GetPort((GrafPtr *)port);
  1091.     }
  1092. }
  1093.  
  1094.  
  1095.  
  1096. /*****************************************************************************/
  1097.  
  1098.  
  1099.  
  1100. #pragma segment GWLayers
  1101. static void    SmartSetGWorld(CGrafPtr port, GDHandle gdh)
  1102. {
  1103.     if (gQDVersion)
  1104.         SetGWorld(port, gdh);
  1105.     else
  1106.         SetPort((GrafPtr)port);
  1107. }
  1108.  
  1109.  
  1110.  
  1111.